from django.shortcuts import render,redirect
from QQLoginTool.QQtool import OAuthQQ
from django.views import View
from django.conf import settings
from django import http
from django.http import JsonResponse, HttpResponse, HttpResponseForbidden, HttpResponseServerError
import logging
from django.contrib.auth import login
import re
from django_redis import get_redis_connection

from meiduo_mall.utils.response_code import RETCODE
from .models import OAuthQQUser, OAuthSinaUser
from .utils import generate_openid_signature, check_openid
from users.models import User
from carts.utils import merge_cart_cookie_to_redis
import requests
from .sinaweibopy3 import APIClient
from urllib.parse import urlencode

logger = logging.getLogger('django')
# Create your views here.

class QQAuthURLView(View):

    def get(self, request):

        next = request.GET.get('next') or '/'

        # auth_qq = OAuthQQ(client_id='appid', client_secret='appkey', redirect_uri='QQ登陆成功之后的回调地址', state='登陆成功重定向时会原样带回')
        # auth_qq = OAuthQQ(client_id='101518219', client_secret='418d84ebdc7241efb79536886ae95224', redirect_uri='http://www.meiduo.site:8000/oauth_callback', state=next)
        auth_qq = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET, redirect_uri=settings.QQ_REDIRECT_URI, state=next)

        login_url = auth_qq.get_qq_url()

        return http.JsonResponse({'code': RETCODE.OK, 'login_url':login_url, 'errmsg': 'OK'})


class QQAuthView(View):

    def get(self, request):

        code = request.GET.get('code')

        if code is None:
            return HttpResponseForbidden('缺少code')

        auth_qq = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                          redirect_uri=settings.QQ_REDIRECT_URI)
        try:
            access_token = auth_qq.get_access_token(code)

            openid = auth_qq.get_open_id(access_token)
        except Exception as e:
            logger.error(e)
            return HttpResponseServerError('OAuth2.0认证失败')

        try:
            oAuth_model = OAuthQQUser.objects.get(openid = openid)

            user = oAuth_model.user

            login(request, user)

            next = request.GET.get('state') or '/'

            response = redirect(next)

            response.set_cookie('username', user.username, max_age=settings.SESSION_COOKIE_AGE)

            merge_cart_cookie_to_redis(request, response)

            return response

        except OAuthQQUser.DoesNotExist:

            openid = generate_openid_signature(openid)
            return render(request, 'oauth_callback.html', {'openid': openid})

    def post(self, request):

        query_dict = request.POST
        mobile = query_dict.get('mobile')
        password = query_dict.get('password')
        sms_code = query_dict.get('sms_code')
        openid_sign = query_dict.get('openid')

        # if all([mobile, password, sms_code, openid_sign]):
        if all((query_dict.dict().values())) is False:
            return HttpResponseForbidden('缺少必传参数')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20个的密码')
        if not re.match(r'^1[[345789]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号')

        redis_conn = get_redis_connection('verify_codes')
        sms_code_server_bytes = redis_conn.get('sms_%s' % mobile)

        if sms_code_server_bytes is None:
            return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码已过期'})

        redis_conn.delete('sms_%s' % mobile)

        sms_code_server = sms_code_server_bytes.decode()
        if sms_code != sms_code_server:
            return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码填写错误'})

        openid = check_openid(openid_sign)
        if openid is None:
            return HttpResponseForbidden('openid无效')

        try:
            user = User.objects.get(mobile=mobile)
            if user.check_password(password) is False:
                return HttpResponseForbidden('老用户信息填写不正确')
        except User.DoesNotExist:
            user = User.objects.create_user(username=mobile, password=password, mobile=mobile)

        OAuthQQUser.objects.create(
            openid = openid,
            user = user
            # user_id = user.id
        )

        login(request, user)
        next = request.GET.get('state') or '/'

        response = redirect(next)
        response.set_cookie('username', user.username, max_age=settings.SESSION_COOKIE_AGE)

        merge_cart_cookie_to_redis(request, response)

        return response


class SinaAuthURLView(View):
    """提供Sina登入url"""
    def get(self, request):
        # 1.获取查询参数
        next = request.GET.get('next') or '/'

        # 2.创建Sina Url参数组建
        data_oauth = {
            'client_id': settings.SINA_CLIENT_ID,
            'redirect_uri': settings.SINA_REDIRECT_URI,
            'state': next,
            'response_type': 'code'
        }

        # 构建url
        sina_url = 'https://api.weibo.com/oauth2/authorize?' + urlencode(data_oauth)
        print(sina_url)

        # 3.调用它里面的get_qq_url方法 得到拼接好的qq登入url
        # login_url = oauth.get_qq_url()
        # 4.响应
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'login_url': sina_url})


class SinaAuthView(View):
    def get(self, request):
        # 1.获取查询字符串code
        code = request.GET.get('code')

        # 2.校验是否回去到code
        if code is None:
            return HttpResponseForbidden('缺少access_token')

        # 3.创建Sian Url参数组建
        data_oauth = {
            'client_id': settings.SINA_CLIENT_ID,
            'client_secret': settings.SINA_CLIENT_SECRET,
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': settings.SINA_REDIRECT_URI,

        }

        # 构建url
        sina_url = 'https://api.weibo.com/oauth2/access_token?' + urlencode(data_oauth)


        # 发送请求
        try:
            response = requests.post(sina_url)
            print(response)

            # 提取数据
            data = response.text
            print(data)

            # 转化为字典
            data = eval(data)

        except:
            raise Exception('Sina请求失败')

        try:
            # 4.得到access_token
            uid = data.get('access_token')
            print(type(uid))
            print(uid)

        except Exception as e:
            logger.error(e)
            return HttpResponseServerError('OAuth 2.0认证失败')

        # 5. 查询uid
        try:
            sina_model = OAuthSinaUser.objects.get(uid=uid)
            # 查询到uid说此sina用户已绑定美多用户，代表登入成功
            user = sina_model.user
            # 状态保持
            login(request, user)
            next = request.GET.get('state') or '/'
            # 向浏览器的cookie中存储username
            response = redirect(next)
            response.set_cookie('username', user.username, max_age=settings.SESSION_COOKIE_AGE)

            # 登录成功合并购物车
            merge_cart_cookie_to_redis(request, response)
            # 重定向到来源界面
            return response

        except OAuthSinaUser.DoesNotExist:
            # 说明openid还没有绑定美多用户，渲染一绑定页面
            return render(request, 'sina_oauth_callback.html', {"uid": uid})

    def post(self, request):
        """uid绑定用户逻辑"""

        # 1.接收表单数据
        query_dict = request.POST
        mobile = query_dict.get('mobile')
        password = query_dict.get('password')
        sms_code = query_dict.get('sms_code')
        uid = query_dict.get('uid')

        # 2.校验
        if all([mobile, password, sms_code, uid]) is False:
            return HttpResponseForbidden('缺少必传参数')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseForbidden('请输入8-20位的密码')
        if not re.match(r'^1[345789]\d{9}$', mobile):
            return HttpResponseForbidden('请输入正确的手机号码')

        # 创建redis连接对象
        redis_conn = get_redis_connection('verify_codes')

        # 获取redis数据库中当前用户短信验证码
        sms_code_server_bytes = redis_conn.get('sms_%s' % mobile)

        # 删除已经取出的短信验证码,让它只能被用一次
        redis_conn.delete('sms_%s' % mobile)

        # 判断redis中短信验证码过期
        if sms_code_server_bytes is None:
            return JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码已过期'})

        # 将bytes类型转换为字符串类型
        sms_code_server = sms_code_server_bytes.decode()

        # 用户填写的和redis中的短信验证码是否一致
        if sms_code != sms_code_server:
            return JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码填写错误'})

        # 3.根据手机号字段查询user表
        try:
            # 3.1 如果通过mobile字段查询到用户  说明此用户是已有账号的美多老用户
            user = User.objects.get(mobile=mobile)

            # 3.1.1 如果是老用户还要检验用户密码是否正确
            if user.check_password(password) is False:
                return HttpResponseForbidden('老用户信息填写不正确')
        except User.DoesNotExist:

            # 3.2 如果没有查询到用户，说明他是一个美多新用户
            # 3.3 如果是新用户，就常见一个新的user 用户名就用mobile
            user = User.objects.create_user(username=mobile, password=password, mobile=mobile)

        # 4. 创建OAuthQQUser 新的记录保存openid 及 user
        OAuthSinaUser.objects.create(
            uid=uid,
            user=user,
        )

        # 5. 状态保持
        login(request, user)
        # 获取state 界面来源
        next = request.GET.get('state') or '/'
        # 创建响应对象
        response = redirect(next)
        response.set_cookie('username', user.username, max_age=settings.SESSION_COOKIE_AGE)

        # 登录成功合并购物车
        merge_cart_cookie_to_redis(request, response)

        # 6. 重定向到指定来源界面
        return response






